
#include <Inklude/IkCLua.h> 
#include <Inklude/ikCString.h>
#include <memory>

extern "C" {
#include <lua/luaconf.h>
#include <lua/lua.h>
#include <lua/lualib.h>
#include <lua/lauxlib.h>
}


using namespace Inklude;
using namespace std;


ikCLua::ikCLua() {
	m_pErrorHandler = NULL;

	m_pScriptContext = lua_open();
	
	luaopen_base(m_pScriptContext);
	luaopen_string(m_pScriptContext);
	luaopen_math(m_pScriptContext);
	luaopen_debug(m_pScriptContext);
	luaopen_table(m_pScriptContext);
	luaL_openlibs (m_pScriptContext); 
}


//ikCLua::ikCLua(HWND handle) {
//	m_pErrorHandler = NULL;
//
//	m_pScriptContext = lua_open();
//	
//	luaopen_base(m_pScriptContext);
//	luaopen_string(m_pScriptContext);
//	luaopen_math(m_pScriptContext);
//	luaopen_debug(m_pScriptContext);
//	luaopen_table(m_pScriptContext);
//	luaL_openlibs (m_pScriptContext); 
//	m_hMain = handle;
//}


ikCLua::~ikCLua() {
	if(m_pScriptContext)
		lua_close(m_pScriptContext);
}



static std::string findScript(const char *pFname)
{
	FILE *fTest;

	char drive[_MAX_DRIVE];
	char dir[_MAX_DIR];
	char fname[_MAX_FNAME];
	char ext[_MAX_EXT];

    _splitpath_s(pFname, drive, dir, fname, ext );
	//_splitpath( pFname, drive, dir, fname, ext );

	std::string strTestFile = (std::string) drive + dir + "Scripts\\" + fname + ".LUB";
    fopen_s(&fTest, strTestFile.c_str(), "r");
	if(fTest == NULL)
	{
		//not that one...
		strTestFile = (std::string) drive + dir + "Scripts\\" + fname + ".LUA";
		fopen_s(&fTest, strTestFile.c_str(), "r");
	}

	if(fTest == NULL)
	{
		//not that one...
		strTestFile = (std::string) drive + dir + fname + ".LUB";
		fopen_s(&fTest, strTestFile.c_str(), "r");
	}

	if(fTest == NULL)
	{
		//not that one...
		//not that one...
		strTestFile = (std::string) drive + dir + fname + ".LUA";
		fopen_s(&fTest, strTestFile.c_str(), "r");
	}

	if(fTest != NULL)
	{
		fclose(fTest);
	}

	return strTestFile;
}



bool ikCLua::RunScriptFile(const char *pFname)
{
	std::string strFilename = findScript(pFname);
	const char *pFilename = strFilename.c_str();

	if (0 != luaL_loadfile(m_pScriptContext, pFilename))
	{
		if(m_pErrorHandler)
		{
			char buf[256];
			sprintf_s(buf, "Lua Error - Script Load\nScript Name:%s\nError Message:%s\n", 
				pFilename, luaL_checkstring(m_pScriptContext, -1));
			m_pErrorHandler(buf);
		}
		return false;
	}
	if (0 != lua_pcall(m_pScriptContext, 0, LUA_MULTRET, 0))
	{
		if(m_pErrorHandler)
		{
			char buf[256];
			sprintf_s(buf, "Lua Error - Script Run\nScript Name:%s\nError Message:%s\n", 
				pFilename, luaL_checkstring(m_pScriptContext, -1));
			m_pErrorHandler(buf);
		}
		return false;
	}
	return true;
}


bool ikCLua::RunString(const char *pCommand)
{
	string error("Lua Error - String ");
	if (0 != luaL_loadbuffer(m_pScriptContext, pCommand, strlen(pCommand), NULL))
	{
		if(m_pErrorHandler)
		{
			char buf[256];
			sprintf_s(buf, "Lua Error - String Load\nString:%s\nError Message:%s\n", 
				pCommand, luaL_checkstring(m_pScriptContext, -1));
			
			m_pErrorHandler(buf);
		}
		return false;
	}


	if (0 != lua_pcall(m_pScriptContext, 0, LUA_MULTRET, 0))
	{
		if(m_pErrorHandler)
		{
			char buf[256];
			sprintf_s(buf, "Lua Error - String Run\nString:%s\nError Message:%s\n", 
				pCommand, luaL_checkstring(m_pScriptContext, -1));

			m_pErrorHandler(buf);
		}
		return false;
	}
	return true;
}


const char* ikCLua::GetErrorString(void)
{
	return luaL_checkstring(m_pScriptContext, -1);
}



bool ikCLua::AddFunction(const char *pFunctionName, pfLuaFunction pfFunction)
{
	lua_register(m_pScriptContext, pFunctionName, pfFunction);
	functionNames.push_back(new string(pFunctionName));
	return true;
}



void ikCLua::ConstructFunctionTable(const char *tableName)
{
	vector<string *>::iterator i;
	string luaCode(tableName);
	luaCode += " = { ";

	bool first = true;

	for (i = functionNames.begin(); i != functionNames.end(); i++) {
		const char *functionName = (*i)->c_str();

		if (first)	
			first = false;
		else 
			luaCode += ", ";


		luaCode += functionName;
		luaCode += " = ";
		luaCode += functionName;
		delete (*i);
	}
	luaCode += " }";
	functionNames.clear();

	luaL_dostring(m_pScriptContext, luaCode.c_str());		
}


void ikCLua::DoString(const char* command) {
	luaL_dostring(m_pScriptContext, command);
}



const char* ikCLua::GetStringArgument(int num, const char *pDefault)
{
	return luaL_optstring(m_pScriptContext, num, pDefault);
}



double ikCLua::GetNumberArgument(int num, double dDefault)
{
	return luaL_optnumber(m_pScriptContext, num, dDefault);
}


void* ikCLua::GetPointerArgument (int num, double dDefault) 
{
	return (void*)((int)luaL_optnumber(m_pScriptContext, num, dDefault));
}



void ikCLua::PushString(const char *pString)
{
	lua_pushstring(m_pScriptContext, pString);
}



void ikCLua::PushNumber(double value)
{
	lua_pushnumber(m_pScriptContext, value);
}

void ikCLua::PushPointer(int value) {
	lua_pushnumber(m_pScriptContext, (double)value);
}

double ikCLua::GetNumber(const char* varName)
{
	lua_getglobal(m_pScriptContext, varName);
	return (lua_tonumber(m_pScriptContext, -1));
}

const char* ikCLua::GetString(const char* varName)
{
	lua_getglobal(m_pScriptContext, varName);
	return (lua_tostring(m_pScriptContext, -1));
}

double ikCLua::GetNumberFromTable (const char* tableName, 
								   const char* fieldName)
{
	lua_getglobal(m_pScriptContext, tableName);
	return getNumberField(fieldName);
}


const char* ikCLua::GetStringFromTable (const char* tableName, 
										const char* fieldName)
{
	lua_getglobal(m_pScriptContext, tableName);
	return getStringField(fieldName);
}

const char* ikCLua::getStringField(const char* fieldName)
{
	lua_pushstring(m_pScriptContext, fieldName);
	lua_gettable(m_pScriptContext, -2);
	if (!lua_isstring(m_pScriptContext, -1))
	{
		printf("Data you request is not number\n");
	}
    shared_ptr<std::string> strResult(new std::string(lua_tostring(m_pScriptContext, -1)));
	string result(lua_tostring(m_pScriptContext, -1));
    m_retStrVec.push_back(strResult);
    return strResult->c_str();
}

double ikCLua::getNumberField(const char* fieldName)
{
	lua_pushstring(m_pScriptContext, fieldName);
	lua_gettable(m_pScriptContext, -2);
	if (!lua_isnumber(m_pScriptContext, -1))
	{
        printf("Data you request is not number\n");
	}
	double result = lua_tonumber(m_pScriptContext, -1);
	lua_pop(m_pScriptContext, 1);
	return result;
}

void ikCLua::ExecLuaFile(const char* fileName)
{
	luaL_dofile(m_pScriptContext, fileName);
}
